package server;

import classLoader.CatClassLoader;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import servlet.HttpServlet;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * MiniCat的主类
 */
public class BootStrap {
    /*
    定义socket监听的端口号
     */
    private int port = 8080;

    /**
     * key: url-pattern标签的值
     * value: servlet-class标签的值，通过反射获取到的对象 class.forName("servlet-class的值");
     */
    private Map<String, HttpServlet> servletMap = new HashMap<>();

    public int getPort() {
        return port;
    }
    public void setPort(int port) {
        this.port = port;
    }

    /**
     * MiniCat的启动入口
     * @param args
     */
    public static void main(String[] args) {
        BootStrap bootStrap = new BootStrap();
        try {
            bootStrap.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * MiniCat启动需要初始化展开的一些操作
     */
    public void start() throws Exception {

        loadServlet();

        //定义一个线程池
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2,
                                                             5,
                                                                60000,
                                                                             TimeUnit.MILLISECONDS,
                                                                             new ArrayBlockingQueue<>(50),
                                                                             Executors.defaultThreadFactory(),
                                                                             new ThreadPoolExecutor.AbortPolicy()
                                                                    );

        /*
           完成minicat1.0版本 （浏览器请求http://lcoalhost:8080,返回一个固定的字符串到页面）
         */
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println(port+"======>Minicat  Start");

        /*
         * 完成tomcat4.0版本
         * 实现多线程访问
         */
       /* while (true){
            Socket socket = serverSocket.accept();
            new RequestProcessor(socket,servletMap).start();
        }*/


        /*
         * 完成tomcat5.0版本
         * 使用线程池来实现多线程访问
         */
        while (true){
            Socket socket = serverSocket.accept();
            poolExecutor.execute(new RequestProcessor(socket,servletMap));
        }

    }



    /**
     * 加载解析web.xml文件，初始化servlet,如下：
     * <web-app>
     *     <servlet>
     *         <servlet-name>lagouServlet</servlet-name>
     *         <servlet-class>servlet.LagouServlet</servlet-class>
     *     </servlet>
     *     <servlet-mapping>
     *         <servlet-name></servlet-name>
     *         <url-pattern>/lagou</url-pattern>
     *     </servlet-mapping>
     * </web-app>
     */
    private void loadServlet() throws Exception{
        //读取webapps,解析web.xml，建立uri与servlet之间的映射关系
        URI webapps = this.getClass().getClassLoader().getResource("webapps").toURI();
        File file = new File(webapps);
        if(file.exists()){
            //判断是否是目录
            if(file.isDirectory()){// webapps/servelt1
                File[] subFiles = file.listFiles();
                for (File subFile:subFiles){
                    if (subFile.isDirectory()){//servet1
                        //加载web.xml
                        doLoadServlet(subFile);
                    }
                }
            }
        }

    }

    /**
     *  解析web.xml
     * @param webFile
     */
    private void doLoadServlet(File webFile) {
        FileInputStream fis = null;
        SAXReader saxReader = new SAXReader();
        String absolutePath = webFile.getAbsolutePath();
        CatClassLoader catClassLoader = new CatClassLoader(absolutePath);
        File webxml = new File(absolutePath + File.separator + "web.xml");
        if (!webxml.exists())
            return;
        try {
            fis = new FileInputStream(webxml);
            Document document = saxReader.read(fis);
            Element rootElement = document.getRootElement();
            List<Element> servletNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < servletNodes.size(); i++) {
                Element servletNode = servletNodes.get(i);
                // <servlet-name>lagouServlet</servlet-name>
                Element servletNameNode = (Element)servletNode.selectSingleNode("//servlet-name");
                String servletName = servletNameNode.getStringValue();
                //<servlet-class>com.lagou.servlet.LagouServlet</servlet-class>
                Element servletClassNode = (Element)servletNode.selectSingleNode("//servlet-class");
                String servletClass = servletClassNode.getStringValue();
                //使用xpath表达式获取对应的servlet-mapping
                Element servletMappingNode = (Element)rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name= '" + servletName + "']");
                //<url-pattern>/lagou</url-pattern>
                Element urlPatternNode = (Element)servletMappingNode.selectSingleNode("//url-pattern");
                String urlPattern = urlPatternNode.getStringValue();
                //通过自定义类加载器获取到Class对象
                Class<?> aClass = catClassLoader.loadClass(servletClass);
                servletMap.put(urlPattern,(HttpServlet) aClass.newInstance());

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
